/******************************************************************************/
/* @ All Rights Reserved Copyright (C) 2015 broada,Ltd.                       */
/*                                                                            */
/*  NAME      = yongyou_parse.c                                               */
/*  NOTE      =                                                               */
/*  DATE      = 2016/11/08 by guojq                                           */
/******************************************************************************/
#include <stdio.h>
#include <string.h>
#include <openssl/aes.h>
#include <openssl/rand.h>
#include <zlib.h>
#include <errno.h>

#include "frcomm.h"
#include "frmem.h"
#include "frlog.h"
#include "frreport_comm.h"
#include "frgzip_decompress.h"

#include "yongyou_parse.h"

#ifdef FR_HTTP_TEST
static void hexdump(
        FILE *f,
        const char *title,
        const unsigned char *s,
        int l)
{
    int n = 0;

    fprintf(f, "%s", title);
    for (; n < l; ++n) {
        if ((n % 16) == 0) {
            fprintf(f, "\n%04x", n);
        }
        fprintf(f, " %02x", s[n]);
    }

    fprintf(f, "\n");
}
#endif

//zc nc
//---------
static void long2bytes(char *p_in, long long sd)
{
    //byte[] dd = new byte[8];
    for (int i = 7; i >= 0; i--)
    {
        p_in[i] = sd;
        sd >>= 8;
    }
    return;
}
static char* genAesKey(int index)
{
    int length = 16;
    char *key = (char *)malloc(length);
    int count = length / 8;
    char tempBytes[8] = {0};
    long long tempLong = 0LL;

    memset(key, 0x00, length);
    for (int i = 0; i < count; i++)
    {
        tempLong = (unsigned long long)(-2719509405472134292LL + index) >> ((i + 1) * 2);
        long2bytes(tempBytes, tempLong);
        memcpy(key + i*8, tempBytes, 8);
    }
    return key;
}

int parseYongYou(Frbyte_Packet *p_st_data, Frbyte_Packet *p_st_data_out)
{
    int i_ret = 0;
    uint32_t u32_len = 0;
    char arr_tmp[5];
    uint8_t key;
    int index = 0;

    int nr_of_bits = 0;
    char *p_key = NULL;
    AES_KEY aes_key;

    int i_use = 0;
    int i_left = 0;
    char arr_aes_encode[AES_BLOCK_SIZE];
    unsigned char arr_decode[AES_BLOCK_SIZE];
    char *p_decode = NULL;

    char *p_uncompress = NULL;
    uLongf i_uncompress = 0;

    if (p_st_data == NULL)
        return FR_FAIL;

#ifdef YONGYOU_DEBUG
    {
        char *p_out = NULL;
        bytebuff_print(p_st_data, bytebuff_getPosition(p_st_data), 20, &p_out);
        if (p_out)
        {
            printf("%s\n",p_out);
            frfree(p_out);
        }
    }
#endif
    //取长度
    i_ret = bytebuff_get_int(p_st_data, 4, &u32_len, BYTE_BIG_ENDIAN);
    if(i_ret == FR_FAIL)
        return FR_FAIL;

    if(u32_len != (unsigned int) bytebuff_remaining(p_st_data))
        return FR_FAIL;

    //确认用友的rmi协议
    i_ret = bytebuff_get_bytes(p_st_data, arr_tmp, 3);
    if(i_ret == FR_FAIL)
        return FR_FAIL;

//    if(memcmp(arr_tmp, "\x72\x71\x89", 3) != 0)
//        return FR_FAIL;

    i_ret = bytebuff_skip(p_st_data, 1);
    if(i_ret == FR_FAIL)
        return FR_FAIL;

    i_ret = bytebuff_get_char(p_st_data, &key);
    if(i_ret == FR_FAIL)
        return FR_FAIL;

    i_left = bytebuff_remaining(p_st_data);
    i_uncompress = i_left * 4 + 1;

    if (i_left < AES_BLOCK_SIZE)
        return FR_FAIL;

    //aes解码后的字符串
    p_decode = (char *)frmalloc(i_left + 1);
    if (p_decode == NULL)
        return FR_FAIL;
    memset(p_decode, 0x00, sizeof(i_left + 1));

    //计算aes的key
    nr_of_bits = 8 * 16;
    index = key & 0x7F;
    p_key = genAesKey(index);
    i_ret = AES_set_decrypt_key((const unsigned char*)p_key, nr_of_bits, &aes_key);

    while (i_left)
    {
        int i_read_len = AES_BLOCK_SIZE;

        i_ret = bytebuff_get_bytes(p_st_data, arr_aes_encode, AES_BLOCK_SIZE);
        if(i_ret == FR_FAIL)
            goto error;

        //aes解码
        AES_decrypt((unsigned char *)arr_aes_encode,arr_decode, &aes_key);
        //去除连续的2个100
        {
            int i = 0;
            for (i=0;i<AES_BLOCK_SIZE;i++)
            {
                if (arr_decode[i] == 100)
                {
                    if (i + 1 < i_read_len && arr_decode[i+1] == 100)
                    {
                        memmove(arr_decode + i + 1, arr_decode + i + 2, i_read_len - i - 1);
                        i_read_len -= 1;
                    }
                    continue;
                }
            }
        }
        memcpy(p_decode + i_use, arr_decode, i_read_len);

        i_left -= AES_BLOCK_SIZE;
        if (i_left == 0)
        {
            i_use += i_read_len;
            break;
        }
        if (i_left < 0)
            goto error;
        i_use += i_read_len;
    }

//    {
//        FILE *fp;
//        fp = fopen("encode_1.zip", "w+");
//
//        fwrite(p_decode, i_use, 1, fp);
//        fclose(fp);
//    }

    i_ret = frgzip_flush_decompress((Byte *)p_decode, i_use, &p_uncompress, &i_uncompress);
    if (i_ret != FR_SUCC)
    {
        //FRLOG_INFO("gzip err,len=%d\n", i_use);
        goto error;
    }

#ifdef YONGYOU_DEBUG
    if (i_ret == FR_SUCC)
    {
        char *p_out = NULL;
        Frbyte_Packet *p_st_tmp_bf = NULL;

        p_st_tmp_bf = bytebuff_creat();
        bytebuff_add(p_st_tmp_bf, p_uncompress, i_uncompress);
        bytebuff_print(p_st_tmp_bf, 0, i_uncompress, &p_out);
        if (p_out)
        {
            printf("========\n%s\n=======\n",p_out);
            frfree(p_out);
        }
        bytebuff_free(&p_st_tmp_bf);
    }
#endif
    bytebuff_add(p_st_data_out, p_uncompress, i_uncompress);

    frfree(p_decode);

    return FR_SUCC;
error:
    if (p_decode)
        frfree(p_decode);
    if (p_uncompress)
        frfree(p_uncompress);
    return FR_FAIL;
}

